#!/usr/bin/env python
"""Script to run openlibrary server.

USAGE:

* Run openlibrary http server at port 8080.

    $ ./scripts/openlibrary-server infogami.yml startserver 8080

* Run openlibrary as fastcgi server at port 7070

    $ ./scripts/openlibrary-server infogami.yml startserver fastcgi 8080

* Run openlibrary as gunicorn server at port 8080

    $ ./scripts/openlibrary-server infogami.yml startserver --gunicorn -b 0.0.0.0:8080
"""
import os
import sys

import web
import yaml
from gunicorn.app.base import Application


def setup_env():
    # make sure PYTHON_EGG_CACHE is writable
    os.environ['PYTHON_EGG_CACHE'] = "/tmp/.python-eggs"

    # required when run as fastcgi
    os.environ['REAL_SCRIPT_NAME'] = ""

    sys.path.append('conf')


def start_server():
    import _init_path  # noqa: F401  Imported for its side effect of setting PYTHONPATH

    args = sys.argv[1:]

    if len(args) < 1 or sys.argv[0] in ['-h', '--help']:
        print(
            "USAGE: %s configfile [subcommand] [arguments]" % (sys.argv[0]),
            file=sys.stderr,
        )
        sys.exit(1)

    configfile, args = args[0], args[1:]
    load_infogami(configfile)

    import infogami

    infogami.run(args)


def load_infogami(config_file):
    import infogami
    from infogami import config
    from infogami.utils import delegate  # noqa: F401 side effects may be needed

    config.plugin_path += ['openlibrary.plugins']
    config.site = "openlibrary.org"

    infogami.load_config(config_file)
    setup_infobase_config(config_file)
    config.middleware.append(https_middleware)


def setup_infobase_config(config_file):
    """Reads the infoabse config file and assign it to config.infobase.
    The config_file is used as base to resolve relative path, if specified in the config.
    """
    from infogami import config

    if config.get("infobase_config_file"):
        dir = os.path.dirname(config_file)
        path = os.path.join(dir, config.infobase_config_file)
        with open(path) as f:
            config.infobase = yaml.safe_load(f)


class BaseWSGIServer(Application):
    def __init__(self, config_file):
        self.config_file = config_file
        Application.__init__(self)

    def init(self, parser, opts, args):
        pass

    def load(self):
        import _init_path  # noqa: F401  Imported for side effect of setting PYTHONPATH

        load_infogami(self.config_file)

        import infogami

        infogami._setup()
        wsgi_app = self.get_wsgi_app()
        # setup middleware for handling /static
        wsgi_app = web.httpserver.StaticMiddleware(wsgi_app)
        return wsgi_app

    def get_wsgi_app(self):
        raise NotImplementedError


class OLWSGIServer(BaseWSGIServer):
    def get_wsgi_app(self):
        from infogami import config
        from infogami.utils import delegate

        return delegate.app.wsgifunc(*config.middleware)


def https_middleware(app):
    """Hack to support https even when the app server http only.

    This makes the redirects and web.changequery work correctly with https.

    The nginx configuration has changed to add the following setting:

        proxy_set_header X-Scheme $scheme;

    Using that value to overwrite wsgi.url_scheme in the WSGI environ,
    which is used by all redirects and other utilities.
    """

    def wrapper(environ, start_response):
        if environ.get('HTTP_X_SCHEME') == 'https':
            environ['wsgi.url_scheme'] = 'https'
        return app(environ, start_response)

    return wrapper


def main():
    setup_env()

    if "--gunicorn" in sys.argv:
        sys.argv.pop(sys.argv.index("--gunicorn"))
        configfile = sys.argv.pop(1)
        server = OLWSGIServer(configfile)
        server.run()
    else:
        start_server()


if __name__ == "__main__":
    main()
